#pragma once1

#include <iostream>
#include <vector>
#include <pthread.h>

#include "Sem.hpp"
#include "Mutex.hpp"
#include <vector>

// 环形队列，生产者和消费者(同步，互斥)
// 生产者先申请资源，放入到缓存剩余空间中
// 消费者也申请资源，从缓存空间中拿取资源
namespace RingBufferModule
{
    using namespace SemModule;
    using namespace LockModule;

    // RingQueue
    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap) : _cap(cap), _productor_sem(cap), _consumer_sem(0), _productor_index(0), _consumer_index(0), Rbuffer(cap)
        {}

        ~RingBuffer()
        {
        }

        void Equeue(const T &in)
        {
            _productor_sem.P();//空间资源--
            {
                //申请信号量之后申请锁
                Lockguard lockguard(_productor_mutex);
                Rbuffer[_productor_index] = in;//放入数据
                _productor_index++;
                _productor_index %= _cap;
            }
            _consumer_sem.V();//数据资源++
        }

        void Pop(T &out)
        {
            _consumer_sem.P();
            {
                Lockguard lockguard(_consumer_mutex);
                out = Rbuffer[_consumer_index];
                _consumer_index++;
                _consumer_index %= _cap;
            }
            _productor_sem.V();//空间资源++
        }

    private:
        int _cap;                  // 环形队列大小
        std::vector<T> Rbuffer; // 利用数组来模拟环形队列

        Sem _productor_sem; // 分别对应生产者和消费者的信号量
        Sem _consumer_sem;

        // 两把锁，方便生产者和消费者访问不同位置的时候，能够并发的向缓存中写入以及从缓存中拿出数据，两把锁分别用来
        // 完成生产者之间，消费者之间的互斥关系

        Mutex _productor_mutex;
        Mutex _consumer_mutex;

        // 分别用两个整数标记生产者和消费者访问的位置

        int _productor_index;
        int _consumer_index;
    };
}